﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2022   保留所有权利。
 * CLR版本：4.0.30319.42000
 * 机器名称：DESKTOP-UL84BU5
 * 公司名称：
 * 命名空间：KingerRobot.WanliMDC.Biz
 * 唯一标识：c17ca8d6-8705-4513-84ae-ae7392e00028
 * 文件名：EmsBiz
 * 当前用户域：DESKTOP-UL84BU5
 * 
 * 创建者：zzl
 * 电子邮箱：1003590782@qq.com
 * 创建时间：2022/6/6 8:37:21
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>
using KingerRobot.MexicoSailunMDC.Spi;
using System.ComponentModel.DataAnnotations;

//using MyBatis.DataMapper.Model.ResultMapping;

//using Newtonsoft.Json.Linq;
using System.Linq;

namespace KingerRobot.MexicoSailunMDC.Biz;
/// <summary>
/// Ems 小车任务
/// 业务EMS
/// </summary>
internal class EmsBiz : K8.MDCBB.Biz
{
    private const string _ClassName = nameof(EmsBiz);
    #region 配置参数
    private ParamData Param { get; set; }

    class ParamData
    {
        /// <summary>
        /// AEms 小车取胎位置
        /// </summary>
        public long AEmsLocId { get; set; }

        /// <summary>
        /// BEms 小车取胎位置
        /// </summary>
        public long BEmsLocId { get; set; }
        /// <summary>
        /// Ems 小车1
        /// </summary>
        public long AEmsId { get; set; }
        /// <summary>
        /// Ems 小车1
        /// </summary>
        public string AEmsName { get; set; }

        /// <summary>
        /// Ems2 小车2
        /// </summary>
        public long BEmsId { get; set; }
        /// <summary>
        /// Ems2 小车2
        /// </summary>
        public string BEmsName { get; set; }
    }
    #endregion

    #region PLC 通讯参数
    private ValueData Data { get; set; }
    class ValueData
    {
        #region PLC 上传 WCS Ems A
        /// <summary>
        /// 流水号
        /// </summary>
        public int ATaskNo { get; set; }
        /// <summary>
        /// Ems 完成反馈 流水号
        /// </summary>
        public int ARTaskNo { get; set; }
        /// <summary>
        /// 放胎完成
        /// </summary>
        public int ARFinish { get; set; }

        /// <summary>
        /// 放胎Z
        /// </summary>
        public int ATargetZ { get; set; }

        #endregion


        #region PLC 上传 WCS Ems B
        /// <summary>
        /// 流水号
        /// </summary>
        public int BTaskNo { get; set; }
        /// <summary>
        /// Ems 完成反馈 流水号
        /// </summary>
        public int BRTaskNo { get; set; }
        /// <summary>
        /// 放胎完成【1 完成；0 未完成】
        /// </summary>
        public int BRFinish { get; set; }
        #endregion


        ///// <summary>
        ///// 桁架状态 1=运行中;2=空闲中;3=故障;4=未进入自动;
        ///// </summary>
        //public int REquipStatus { get; set; }
        ///// <summary>
        ///// 标志位 0=桁架运行中;1 =下位可读指令;2=上位可写指令;
        ///// </summary>
        //public int REquipCmdFlag { get; set; }


        /// <summary>
        /// 桁架状态 1=运行中;2=空闲中;3=故障;4=未进入自动;
        /// </summary>
        public int EquipStatus { get; set; }
        /// <summary>
        /// 标志位 0=桁架运行中;1 =下位可读指令;2=上位可写指令;
        /// </summary>
        public int EquipFlag { get; set; }

        public int ErrorNoEMS { get; set; }
        public int ErrorNoA0 { get; set; }
        public int ErrorNoA1 { get; set; }
        public int ErrorNoA2 { get; set; }
        public int ErrorNoA3 { get; set; }
        public int ErrorNoA { get; set; }

        public int ErrorNoB0 { get; set; }
        public int ErrorNoB1 { get; set; }
        public int ErrorNoB2 { get; set; }
        public int ErrorNoB3 { get; set; }
        public int ErrorNoB { get; set; }
        /// <summary>
        /// EMS报警提醒
        /// </summary>
        public int AlarmTips { get; set; }


    }
    #endregion

    #region 缓存
    private CacheData Cache { get; set; }
    class CacheData
    {

        /// <summary>
        /// 流水号A
        /// </summary>
        public int ATaskNo { get; set; }

        /// <summary>
        /// 流水号B
        /// </summary>
        public int BTaskNo { get; set; }

    }
    #endregion

    #region 实时日志
    private StepData Step { get; set; }
    class StepData
    {
        private string _msg = string.Empty;
        public string StepMsg
        {
            get
            {
                return this._msg;
            }
            set
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    this._msg = string.Empty;
                    return;
                }
                this._msg = $"{_ClassName}|{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}>>{value}";
            }
        }
    }
    private void StepMsg(string msg)
    {
        this.Step.StepMsg = msg;
        WriteLog(msg);
    }
    #endregion

    #region 文件日志（运行需要 Nlog 配置）
    private void WriteLog(string message)
    {
        K8.LSF.Client.Log(new K8.LSF.Log { Data = message });
    }
    #endregion

    /// <summary>
    /// 和 PLC 通讯对象
    /// </summary>
    /// 
    private BizData BizData { get; set; }
    public int Execute(BizData writer)
    {
        // Excute 方法外使用 BizData
        this.BizData = writer;
        // 设备故障
        var ErrorNoEMS = 0;
        var ErrorNoEmsMsg = new StringBuilder();
        if (Data.ErrorNoEMS != 0 )
        {
            ErrorNoEMS = Data.ErrorNoEMS;

            try
            {
                // 解析
                var codeEms = Convert.ToString(ErrorNoEMS , 2).PadLeft(64, '0');
                var codeArrEms = codeEms.ToCharArray();
                Array.Reverse(codeArrEms);
                //StepMsg($"ErrorNoA报警 : {Value.ErrorNoA} ，二进制字符串{code},反转后{codeArr.ToJson()}");

                for (int i = 0; i < codeArrEms.Length; i++)
                {
                    if (Convert.ToInt32(codeArrEms[i].ToString()) == 1)
                    {
                        ErrorNoEmsMsg.Append($"{Data.ErrorNoEMS}-{DictionaryData.GetEmsError(i + 1)} ");
                    }
                }
            }
            catch
            {

            }
        }
        //Alarm.Instance.AddAlarmV2(Param.AEmsId, ErrorNoEMS, $"{Data.ErrorNoEMS}", ErrorNoEmsMsg.ToString(), Data.ATaskNo);

        var ErrorNoA = 0;
        var ErrorNoAMsg = new StringBuilder();
        if (Data.ErrorNoA0 != 0 || Data.ErrorNoA1 != 0 || Data.ErrorNoA2 != 0 || Data.ErrorNoA3 != 0 || Data.ErrorNoA != 0 || Data.ErrorNoEMS != 0)
        {
            ErrorNoA = Data.ErrorNoA0 + Data.ErrorNoA1 + Data.ErrorNoA2 + Data.ErrorNoA3 + Data.ErrorNoA + ErrorNoEMS;
            ErrorNoAMsg.Append($"{DictionaryData.GetEmsErrorA0(Data.ErrorNoA0)} |")
                .Append($"{DictionaryData.GetEmsErrorA1(Data.ErrorNoA1)} |")
                .Append($"{DictionaryData.GetEmsErrorA2(Data.ErrorNoA2)} |")
                .Append($"{DictionaryData.GetEmsErrorA3(Data.ErrorNoA3)} |");

            int errorCodeA = 0;
            int errorCodeEms = 0;
            try
            {
                // 解析
                errorCodeA = Data.ErrorNoA;
                errorCodeEms = Data.ErrorNoEMS;
                var code = Convert.ToString(errorCodeA, 2).PadLeft(64, '0');
                var codeEms = Convert.ToString(errorCodeEms, 2).PadLeft(64, '0');
                var codeArr = code.ToCharArray();
                var codeArrEms = codeEms.ToCharArray();
                Array.Reverse(codeArr);
                Array.Reverse(codeArrEms);
                //StepMsg($"ErrorNoA报警 : {Value.ErrorNoA} ，二进制字符串{code},反转后{codeArr.ToJson()}");

                for (int i = 0; i < codeArr.Length; i++)
                {
                    if (Convert.ToInt32(codeArr[i].ToString()) == 1)
                    {
                        ErrorNoAMsg.Append($"{Data.ErrorNoA}-{DictionaryData.GetEmsErrorA(i + 1)} |");
                    }
                }

                for (int i = 0; i < codeArrEms.Length; i++)
                {
                    if (Convert.ToInt32(codeArrEms[i].ToString()) == 1)
                    {
                        ErrorNoAMsg.Append($"{Data.ErrorNoEMS}-{DictionaryData.GetEmsError(i + 1)} |");
                    }
                }
            }
            catch
            {

            }
        }
        else if (Data.EquipStatus == (int)EnumEmsStatus.Fault)
        {
            var msg = new StringBuilder();
            msg.Append("Ems小车1");
            msg.Append(Param.AEmsId);
            msg.Append("Ems异常报警");
            ErrorNoA = 1110;
            ErrorNoAMsg = msg;
            WriteEmsAlarmTips();
        }
        else if (Data.EquipStatus == (int)EnumEmsStatus.NoAuto)//EMSA 手动状态 添加一条报警信息
        {
            var msg = new StringBuilder();
            msg.Append("Ems小车1");
            msg.Append(Param.AEmsId);
            msg.Append("Ems设备状态: 手动");
            ErrorNoA = 2220;
            ErrorNoAMsg = msg;
        }
        Alarm.Instance.AddAlarmV2(Param.AEmsId, ErrorNoA, $"{Data.ErrorNoA0},{Data.ErrorNoA1},{Data.ErrorNoA2},{Data.ErrorNoA3},{Data.ErrorNoA},{Data.ErrorNoEMS}", ErrorNoAMsg.ToString(), Data.ATaskNo);

        var ErrorNoB = 0;
        var ErrorNoBMsg = new StringBuilder();
        if (Data.ErrorNoB0 != 0 || Data.ErrorNoB1 != 0 || Data.ErrorNoB2 != 0 || Data.ErrorNoB3 != 0 || Data.ErrorNoB != 0)
        {
            ErrorNoB = Data.ErrorNoB0 + Data.ErrorNoB1 + Data.ErrorNoB2 + Data.ErrorNoB3 + Data.ErrorNoB;
            ErrorNoBMsg.Append($"{DictionaryData.GetEmsErrorB0(Data.ErrorNoB0)} |")
                .Append($"{DictionaryData.GetEmsErrorB1(Data.ErrorNoB1)} |")
                .Append($"{DictionaryData.GetEmsErrorB2(Data.ErrorNoB2)} |")
                .Append($"{DictionaryData.GetEmsErrorB3(Data.ErrorNoB3)} |");
            int errorCodeB = 0;
            try
            {
                // 解析
                errorCodeB = Data.ErrorNoB;
                var codeB = Convert.ToString(errorCodeB, 2).PadLeft(64, '0');
                var codeArrB = codeB.ToCharArray();
                Array.Reverse(codeArrB);
                //StepMsg($"ErrorNoB报警 : {Value.ErrorNoB} ，二进制字符串{codeB},反转后{codeArrB.ToJson()}");
                for (int i = 0; i < codeArrB.Length; i++)
                {
                    if (Convert.ToInt32(codeArrB[i].ToString()) == 1)
                    {
                        ErrorNoBMsg.Append($"{Data.ErrorNoB}-{DictionaryData.GetEmsErrorB(i + 1)} |");
                    }
                }
            }
            catch
            {

            }
        }
        else if (Data.EquipStatus == (int)EnumEmsStatus.Fault)
        {
            var msg = new StringBuilder();
            msg.Append("Ems小车2");
            msg.Append(Param.AEmsId);
            msg.Append("Ems异常报警");
            ErrorNoB = 1110;
            ErrorNoBMsg = msg;
            WriteEmsAlarmTips();
        }
        else if (Data.EquipStatus == (int)EnumEmsStatus.NoAuto)//EMSB 手动状态 添加一条报警信息
        {
            if (Param.BEmsId != 0)
            {
                var msg = new StringBuilder();
                msg.Append("Ems小车2");
                msg.Append(Param.BEmsId);
                msg.Append("Ems设备状态: 手动");
                ErrorNoB = 2220;
                ErrorNoBMsg = msg;
            }
        }
        Alarm.Instance.AddAlarmV2(Param.BEmsId, ErrorNoB, $"{Data.ErrorNoB0},{Data.ErrorNoB1},{Data.ErrorNoB2},{Data.ErrorNoB3},{Data.ErrorNoB}", ErrorNoBMsg.ToString(), Data.BTaskNo);

        // 返回参数
        var result = 0;

        this.StepMsg($"Ems 小车 1:{Param.AEmsId} | 2:{Param.BEmsId} |位置:{Param.AEmsLocId} |" +
            $"设备状态:{Data.EquipStatus}:{GetEmsEquipStatus(Data.EquipStatus)} | " +
            $"异常状态:{Data.EquipFlag}:{GetEmsSign(Data.EquipFlag)}");

        //创建RPC对象
        var emsService = K8.RSF.Client.Create<ICuringEmsIntoTankService>();
        var curingService = K8.RSF.Client.Create<ICuringService>();
        var taskService = K8.RSF.Client.Create<ITaskService>();
        this.StepMsg($"记录任务号A:{Data.ARTaskNo},任务号B{Data.BRTaskNo}");
       // AB 小车 对象
       var beanA = new EmsBean()
        {
            CacheTaskNo = Cache.ATaskNo,
            ValueTaskNo = Data.ARTaskNo,
            FinishFlag = Data.ARFinish,
            EmsId = Param.AEmsId,
            LocId = Param.AEmsLocId,
        };
        // 小车A完成
        var (numA, resultA) = FinishEmsTask(beanA, emsService, curingService);

        var beanB = new EmsBean()
        {
            CacheTaskNo = Cache.BTaskNo,
            ValueTaskNo = Data.BRTaskNo,
            FinishFlag = Data.BRFinish,
            EmsId = Param.BEmsId,
            LocId = Param.BEmsLocId,
        };
        // 小车B完成
        var (numB, resultB) = FinishEmsTask(beanB, emsService, curingService);

        if (numA > 0 || numB > 0)
        {
            return result;
        }

        //// "EmsBiz|2022-07-19 16:23:24.289>>Ems 小车 1:10100101 | 2:10100102 |位置:20090101 |设备状态:2:空闲中 | 异常状态:4:其他Ems4"
        if (Data.EquipStatus != (int)EnumEmsStatus.Ldle || Data.EquipFlag != (int)EnumEmsAck.UpperRead)
        {
            this.StepMsg($"设备非空闲 和 不允许写 无法继续工作.");
            // 非空闲，不允许尚未可写指令
            return result;
        }

        //解决-双车任务，一个完成另一个没完成
        //FinishRemainTasks();

        //this.StepMsg($"######EMS任务开始创建.");
        //// 小车A【创建Ems负责任务、创建异常任务（无绑定Ems）】
        //var emsATask = CreateEmsTaskResult(beanA, emsService, taskService);
        //if (!emsATask.isExecute)
        //{
        //    this.StepMsg($"EmsA {Param.AEmsId}任务完成正在执行.");
        //    // 一个小车正在执行退出
        //    return result;
        //}
        //// 小车B【创建Ems负责任务、创建异常任务（无绑定Ems）】
        //var emsBTask = CreateEmsTaskResult(beanB, emsService, taskService);
        //if (!emsBTask.isExecute)
        //{
        //    this.StepMsg($"EmsB {Param.AEmsId}任务完成正在执行.");
        //    // 一个小车正在执行退出
        //    return result;
        //}

        var (emsATask, emsBTask) = CreateEmsTaskResult(beanA, beanB, emsService, taskService);

        this.StepMsg($"######EMS任务--{emsATask.bizTaskCmdXZ?.TaskNo},--{emsBTask.bizTaskCmdXZ?.TaskNo}创建成功.");
        var taskCmd_A = emsATask.bizTaskCmdXZ;
        var ems_A = emsATask.bizTaskCmdXZ?.EmsId ?? 0;

        // 
        if (!emsATask.isExecute && !emsBTask.isExecute)
        {
            // 双车
            BizTaskCmdXZ bizTaskCmdXZ = new()
            {

                TaskNo = emsATask.bizTaskCmdXZ.TaskNo,
                StartX = emsATask.bizTaskCmdXZ.StartX,
                StartZ = emsATask.bizTaskCmdXZ.StartZ,
                SubSize = emsATask.bizTaskCmdXZ.SubSize,
                TargetX = emsATask.bizTaskCmdXZ.TargetX,
                TargetZ = emsATask.bizTaskCmdXZ.TargetZ,


                TaskNoB = emsBTask.bizTaskCmdXZ.TaskNo,
                StartBX = emsBTask.bizTaskCmdXZ.StartX,
                StartBZ = emsBTask.bizTaskCmdXZ.StartZ,
                SubSizeB = emsBTask.bizTaskCmdXZ.SubSize,
                TargetBX = emsBTask.bizTaskCmdXZ.TargetX,
                TargetBZ = emsBTask.bizTaskCmdXZ.TargetZ,
            };

            //this.StepMsg($"######EMS双车任务开始下发emsATask--{emsATask.bizTaskCmdXZ?.ToJson()},");

            //此处需要判断是否空车
            if (emsATask.bizTaskCmdXZ.CmdType == (int)EnumTaskType.EmsEmpty)
            {
                WriteSameABPlc(bizTaskCmdXZ, emsService, true);
            }
            else
            {
                WriteSameABPlc(bizTaskCmdXZ, emsService, false);
            }
            return result;
        }



        if (!emsATask.isExecute)
        {
            this.StepMsg($"######EMS任务A开始下发--{emsATask.bizTaskCmdXZ?.TaskNo},--{emsBTask.bizTaskCmdXZ?.TaskNo}");
            WriteAPlcV2(emsATask.bizTaskCmdXZ, emsService);
            return result;
        }

        if (!emsBTask.isExecute)
        {
            this.StepMsg($"######EMS任务B开始下发--{emsATask.bizTaskCmdXZ?.TaskNo},--{emsBTask.bizTaskCmdXZ?.TaskNo}");
            WriteBPlcV2(emsBTask.bizTaskCmdXZ, emsService);
            return result;
        }

        //var excuteEmsTask = ExcuteEmsTask(taskCmd_A, ems_A, emsService);
        //if (excuteEmsTask == 1)
        //{
        //    return result;
        //}

        //var taskCmd_B = emsBTask.bizTaskCmdXZ;
        //var ems_B = emsBTask.bizTaskCmdXZ?.EmsId ?? 0;
        //ExcuteEmsTask(taskCmd_B, ems_B, emsService);
        return result;
    }

    ///// <summary>
    ///// Ems 小车执行任务
    ///// </summary>
    ///// <param name="bizTaskCmdXZ"></param>
    ///// <param name="emsId"></param>
    ///// <returns>
    ///// 0 向下执行
    ///// 1 停止执行
    ///// </returns>
    //public int ExcuteEmsTask(BizTaskCmdXZ bizTaskCmdXZ, long emsId, ICuringEmsIntoTankService? emsService)
    //{
    //    if (emsId == 0)
    //    {
    //        return 0;
    //    }

    //    if (bizTaskCmdXZ is null)
    //    {
    //        this.StepMsg($"Ems 小车 {emsId} 没有要执行的任务.");
    //        return 0;
    //    }

    //    var excuteSign = ExcuteEmsTaskResult(bizTaskCmdXZ, emsId, emsService);
    //    if (excuteSign == 2)
    //    {
    //        this.StepMsg($"Ems 小车 {emsId} 非异常任务，已经下传指令完成.");
    //        return 1;
    //    }

    //    if (excuteSign == 0)
    //    {
    //        var abnormalSign = ExcuteSelfAbnormal(bizTaskCmdXZ, emsId, emsService);
    //        if (abnormalSign == 1)
    //        {
    //            this.StepMsg($"Ems 小车 {emsId} 异常任务，当前小车异常任务执行.");
    //            // 异常自己处理不执行下面代码
    //            return 1;
    //        }
    //    }

    //    return 0;
    //}

    /// <summary>
    ///// 处理异常（当前小车处理/非当前小车处理）【0：非当前小车处理；1：当前小车处理（不往下执行）】
    ///// </summary>
    ///// <param name="bizTaskCmdXZ"></param>
    ///// <param name="emsId"></param>
    ///// <returns></returns>
    //public int ExcuteSelfAbnormal(BizTaskCmdXZ bizTaskCmdXZ, long emsId, ICuringEmsIntoTankService? emsCurService)
    //{
    //    // 异常
    //    var emsService = K8.RSF.Client.Create<IEmsService>();
    //    // 判断执行的小车车
    //    var abnormalEmsIds = emsService.GetAbnormalEmsIdByStartId(bizTaskCmdXZ.StartLoc);
    //    if (abnormalEmsIds is null)
    //    {
    //        return 0;
    //    }
    //    if (!abnormalEmsIds.Contains(emsId))
    //    {
    //        this.StepMsg($"Ems 小车 {emsId},  另一个小车处理异常.");

    //        return 0;
    //    }

    //    // 下任务(执行)
    //    var mark = WriteABPlc(bizTaskCmdXZ, emsId, emsCurService);
    //    //if (mark > 0)
    //    //{
    //    if (Param.AEmsId == emsId)
    //    {
    //        RuningAPlc();
    //    }
    //    else if (Param.BEmsId == emsId)
    //    {
    //        RuningBPlc();
    //    }
    //    //}

    //    return 1;
    //}

    ///// <summary>
    ///// 执行任务
    ///// </summary>
    ///// <param name="bizTaskCmdXZ"></param>
    ///// <param name="emsId"></param>
    ///// <returns>
    ///// 0 异常；
    ///// 1 非异常(不执行)；
    ///// 2 非异常（不等待）停止向下执行代码【单台任务完成、双胎任务完成、任务上传失败】
    ///// </returns>
    //public int ExcuteEmsTaskResult(BizTaskCmdXZ bizTaskCmdXZ, long emsId, ICuringEmsIntoTankService? emsService)
    //{

    //    if (bizTaskCmdXZ.IsAbnormal)
    //    {
    //        this.StepMsg($"Ems 小车 {emsId} 异常任务.");
    //        return 0;
    //    }

    //    // 不等待
    //    if (bizTaskCmdXZ.PairWait == 0)
    //    {
    //        // 下传任务
    //        var mark = WriteABPlc(bizTaskCmdXZ, emsId, emsService);
    //        if (mark == 0)
    //        {
    //            this.StepMsg($"Ems 小车 {emsId} 上传PLC失败.");
    //            return 2;
    //        }

    //        // 不等待执行
    //        if (Param.AEmsId == emsId)
    //        {
    //            RuningAPlc();
    //        }
    //        else if (Param.BEmsId == emsId)
    //        {
    //            RuningBPlc();
    //        }
    //        return 2;
    //    }

    //    // 完成
    //    if (bizTaskCmdXZ.PairWait == 2)
    //    {
    //        return 2;
    //    }

    //    if (bizTaskCmdXZ.PairWait == 1)
    //    {
    //        // 下传任务
    //        var mark = WriteSameABPlc(bizTaskCmdXZ, emsService);
    //        if (mark == 0)
    //        {
    //            this.StepMsg($"Ems 小车 {emsId} 上传PLC失败.");
    //            return 2;
    //        }
    //        return 2;
    //    }
    //    this.StepMsg($"Ems 小车 {emsId} 配对等待未执行.");
    //    return 1;
    //}

    private int RuningABPlc()
    {

        var mark = this.BizData.WriteData(new
        {
            curFlag = 2,
            EquipFlag = 1,
            AEmptyRun = 0,
        });

        Thread.Sleep(500);
        return mark;
    }
    private int RuningABPlcEmpty()
    {

        var mark = this.BizData.WriteData(new
        {
            curFlag = 2,
            EquipFlag = 1,
            AEmptyRun = 1,
        });

        Thread.Sleep(500);
        return mark;
    }
    /// <summary>
    /// 实际执行
    /// </summary>
    /// <returns></returns>
    private int RuningAPlc()
    {
        this.StepMsg($"######EMS任务下传完成，准备下传确认标志.");
        var mark = this.BizData.WriteData(new
        {
            curFlag = 1,
            EquipFlag = 1,
            AEmptyRun = 0,
        });

        this.StepMsg($"######EMS任务下传完成，确认标志下传完成.");
        Thread.Sleep(500);
        return mark;
    }

    /// <summary>
    /// 实际执行
    /// </summary>
    /// <returns></returns>
    private int RuningBPlc()
    {
        this.StepMsg($"######EMS任务下传完成，准备下传确认标志.");
        //b车单胎任务时 需要a车空跑
        var mark = this.BizData.WriteData(new
        {
            curFlag = 1,
            EquipFlag = 1,
            AEmptyRun = 1,
        });

        this.StepMsg($"######EMS任务下传完成，确认标志下传完成.");
        Thread.Sleep(500);
        return mark;

    }




    private int WriteAPlcV2(BizTaskCmdXZ bizTaskCmdXZ, ICuringEmsIntoTankService? emsService)
    {

        this.StepMsg($"######EMS——A任务开始下传.");

        var mark = this.BizData.WriteData(new
        {
            // 下传字段值
            ATaskNo = bizTaskCmdXZ.TaskNo,
            AStartX = bizTaskCmdXZ.StartX,
            AStartZ = (int)bizTaskCmdXZ.StartZ,
            ASubSize = bizTaskCmdXZ.SubSize,
            ATargetX = bizTaskCmdXZ.TargetX,
            ATargetZ = (int)bizTaskCmdXZ.TargetZ,
            AAllowableDescent = 1,
            ATakeTire = 1,


            BTaskNo = 0,
            BStartX = 0,
            BStartZ = 0,
            BSubSize = 0,
            BTargetX = 0,
            BTargetZ = 0,
            BAllowableDescent = 0,
            BTakeTire = 0,
        });
        this.StepMsg($"######EMS——A任务下传完成.");
        if (mark > 0)
        {
            mark = RuningAPlc();
            // 执行
            //var emsService = K8.RSF.Client.Create<ICuringEmsIntoTankService>();
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNo);
            Cache.ATaskNo = bizTaskCmdXZ.TaskNo;
        }

        this.StepMsg($"######EMS——A任务执行完成.");
        return mark;
    }



    private int WriteBPlcV2(BizTaskCmdXZ bizTaskCmdXZ, ICuringEmsIntoTankService? emsService)
    {
        this.StepMsg($"######EMS——B任务开始下传.");
        var mark = this.BizData.WriteData(new
        {
            // 下传字段值
            BTaskNo = bizTaskCmdXZ.TaskNo,
            BStartX = (int)bizTaskCmdXZ.StartX,
            BStartZ = bizTaskCmdXZ.StartZ,
            BSubSize = bizTaskCmdXZ.SubSize,
            BTargetX = bizTaskCmdXZ.TargetX,
            BTargetZ = (int)bizTaskCmdXZ.TargetZ,
            BAllowableDescent = 1,
            BTakeTire = 1,

            ATaskNo = 0,
            AStartX = 0,
            AStartZ = 0,
            ASubSize = 0,
            ATargetX = 0,
            ATargetZ = 0,
            AAllowableDescent = 0,
            ATakeTire = 0,
        });
        this.StepMsg($"######EMS——B任务下传完成.");
        if (mark > 0)
        {
            RuningBPlc();
            // 执行
            //var emsService = K8.RSF.Client.Create<ICuringEmsIntoTankService>();
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNo);

            Cache.BTaskNo = bizTaskCmdXZ.TaskNo;
        }
        this.StepMsg($"######EMS——B任务执行完成.");
        return mark;
    }

    private int WriteSameABPlc(BizTaskCmdXZ bizTaskCmdXZ, ICuringEmsIntoTankService? emsService, bool isEmpty = false)
    {
        var mark = 0;

        this.StepMsg($"######EMS——AB任务开始下传.");

        if (isEmpty)
        {
            this.StepMsg($"######EMS——AB下发空车");
            mark = this.BizData.WriteData(new
            {
                // 下传字段值
                ATaskNo = bizTaskCmdXZ.TaskNo,
                AStartX = bizTaskCmdXZ.StartX,
                AStartZ = 0,
                ASubSize = bizTaskCmdXZ.SubSize,
                ATargetX = bizTaskCmdXZ.TargetX,
                ATargetZ = 0,
                AAllowableDescent = 1,
                ATakeTire = 1,

                BTaskNo = bizTaskCmdXZ.TaskNoB,
                BStartX = bizTaskCmdXZ.StartBX,
                BStartZ = bizTaskCmdXZ.StartBZ,
                BSubSize = bizTaskCmdXZ.SubSizeB,
                BTargetX = bizTaskCmdXZ.TargetBX,
                BTargetZ = bizTaskCmdXZ.TargetBZ,
                BAllowableDescent = 1,
                BTakeTire = 1,
            });
            if (mark > 0)
            {
                mark = RuningABPlcEmpty();
            }

        }
        else
        {
            this.StepMsg($"######EMS——AB下发非空车");

            mark = this.BizData.WriteData(new
            {
                // 下传字段值
                ATaskNo = bizTaskCmdXZ.TaskNo,
                AStartX = bizTaskCmdXZ.StartX,
                AStartZ = bizTaskCmdXZ.StartZ,
                ASubSize = bizTaskCmdXZ.SubSize,
                ATargetX = bizTaskCmdXZ.TargetX,
                ATargetZ = bizTaskCmdXZ.TargetZ,
                AAllowableDescent = 1,
                ATakeTire = 1,

                BTaskNo = bizTaskCmdXZ.TaskNoB,
                BStartX = bizTaskCmdXZ.StartBX,
                BStartZ = bizTaskCmdXZ.StartBZ,
                BSubSize = bizTaskCmdXZ.SubSizeB,
                BTargetX = bizTaskCmdXZ.TargetBX,
                BTargetZ = bizTaskCmdXZ.TargetBZ,
                BAllowableDescent = 1,
                BTakeTire = 1,
            });
            if (mark > 0)
            {
                mark = RuningABPlc();
            }
        }

        if (mark <= 0)
        {
            return 0;
        }
        // 执行
        //var emsService = K8.RSF.Client.Create<ICuringEmsIntoTankService>();
        if (bizTaskCmdXZ.EmsId == Param.AEmsId)
        {
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNo);
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNoB);
            Cache.ATaskNo = bizTaskCmdXZ.TaskNo;
            Cache.BTaskNo = bizTaskCmdXZ.TaskNoB;
        }
        else
        {
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNoB);
            emsService.ExecuteTask(bizTaskCmdXZ.TaskNo);
            Cache.ATaskNo = bizTaskCmdXZ.TaskNoB;
            Cache.BTaskNo = bizTaskCmdXZ.TaskNo;
        }

        this.StepMsg($"######EMS——AB任务执行完成.");
        return mark;
    }

    /// <summary>
    /// 给4排ems写入报警提醒
    /// </summary>
    /// <returns></returns>
    private int WriteEmsAlarmTips()
    {

        this.StepMsg($"######EMS报警提醒开始下传.");
        var mark = 0;
        try
        {
            mark = this.BizData.WriteData(new
            {
                AlarmTips = 1
            });
        }
        catch (Exception ex)
        {
            this.StepMsg($"######EMS报警提醒下传失败--{ex.ToString()}");
        }
        return mark;
    }




    private (int, CuringBean?) FinishEmsTask(EmsBean emsBean, ICuringEmsIntoTankService? emsService, ICuringService? curingService)
    {
        var emsId = emsBean.EmsId;
        if (emsId == 0)
        {
            return (0, null);
        }
        //2023年10月23日  GHP
        //var emsService = K8.RSF.Client.Create<ICuringEmsIntoTankService>();
        // var curingService = K8.RSF.Client.Create<ICuringService>();

        var cacheTaskNo = emsBean.CacheTaskNo;
        var valueTaskNo = emsBean.ValueTaskNo;
        // 小车任务完成
        if (cacheTaskNo == valueTaskNo && valueTaskNo != 0)
        {
            CuringBean curingBean = curingService.GetCuringMode(valueTaskNo);

            // 小车任务完成
            var finishTask = emsService.FinishTask(valueTaskNo);
            if (finishTask > 0)
            {
                ClearCache(valueTaskNo);
                return (1, curingBean);
            }
            return (0, null);
        }
        return (0, null);
    }


    private void FinishRemainTasks(ITaskService? taskService, ICuringEmsIntoTankService? emsService, ICuringService? curingService)
    {
        //var taskService = K8.RSF.Client.Create<ITaskService>();

        var cmds = taskService.GetExecutedTaskCmds().Where(f => f.EquipId == Param.AEmsId || f.EquipId == Param.BEmsId).ToList();

        if (cmds.Count % 2 == 1)
        {
            var cmd = cmds.OrderBy(f => f.CreateTime).FirstOrDefault();

            var taskId = cmd?.TaskId ?? 0;

            if (taskId == 0)
            {
                return;
            }

            if ((cmd?.PairWait ?? 0) == 0)//送单胎的话，无需走这方面代码
            {
                return;
            }

            var task = taskService.GetTaskById(taskId);

            if (task is null)
            {
                return;
            }

            var isNeedFinish = taskService.IsNeedFinish(task, cmd);

            if (!isNeedFinish)
            {
                return;
            }

            var bean = new EmsBean()
            {
                CacheTaskNo = task?.TaskNo ?? 0,
                ValueTaskNo = task?.TaskNo ?? 0
            };

            FinishEmsTask(bean, emsService, curingService);

        }
    }



    /// <summary>
    /// isExecute = false 不执行
    /// emsId 小车Id
    /// bizTaskCmdXZ 返回坐标
    /// </summary>


    private (emsTaskCreateBean emsATask, emsTaskCreateBean emsBTask) CreateEmsTaskResult(EmsBean emsBeanA, EmsBean emsBeanB, ICuringEmsIntoTankService? emsService, ITaskService? taskService)
    {
        var emsIdA = emsBeanA.EmsId;
        var emsIdB = emsBeanB.EmsId;
        emsTaskCreateBean emsATask = new()
        {
            isExecute = true,
            emsId = emsIdA,
            bizTaskCmdXZ = null,
        };
        emsTaskCreateBean emsBTask = new()
        {
            isExecute = true,
            emsId = emsIdB,
            bizTaskCmdXZ = null,
        };


        if (emsIdA == 0 || emsIdB == 0)
        {
            return (emsATask, emsBTask);
        }

        var locIdA = emsBeanA.LocId;
        var locIdB = emsBeanB.LocId;

        this.StepMsg($"Ems {emsIdA}小车任务查询参数， 2:{Param.BEmsId} |位置:{Param.BEmsLocId} |" +
$"设备状态:{Data.EquipStatus}:{GetEmsEquipStatus(Data.EquipStatus)} | " +
$"异常状态:{Data.EquipFlag}:{GetEmsSign(Data.EquipFlag)}");


        // A小车是否有在执行任务（有：返回）
        var (isExecutedA, taskA, pairWaitA) = IsExecuted(taskService, emsIdA);

        // B小车是否有在执行任务（有：返回）
        var (isExecutedB, taskB, pairWaitB) = IsExecuted(taskService, emsIdB);

        // 未创
        // 已创建: 已执行(单执行\双执行), 都未执行

        if (isExecutedA || isExecutedB)
        {
            this.StepMsg($"Ems 小车正在执行任务2");
            if (Param.AEmsId == emsIdA && isExecutedA)
            {
                Cache.ATaskNo = taskA.TaskNo;
            }

            if (Param.BEmsId == emsIdB && isExecutedB)
            {
                Cache.BTaskNo = taskB.TaskNo;
            }

            return (emsATask, emsBTask);
        }



        // 是否存在 未执行任务
        var cmdIdA = taskA?.CmdId ?? 0;
        this.StepMsg($"cmdIdA {cmdIdA}是否存在");
        var cmdIdB = taskB?.CmdId ?? 0;
        this.StepMsg($"cmdIdB {cmdIdB}是否存在");
        //如果两个放胎位都没有指令 则生成
        //if (cmdIdA == 0 && cmdIdB == 0)
        //{

        if (cmdIdA == 0 && cmdIdB == 0)
        {
            // 双车任务(同时,同步) \ 单车任务
            // 同时给两个小车创建任务
            //(cmdIdA, cmdIdB) = emsService.CreateTask(locIdA, locIdB, emsIdA, emsIdB);
            var emsTaskResult = emsService.CreateTaskV2(locIdA, locIdB, emsIdA, emsIdB);
            cmdIdA = emsTaskResult.CmdIdA;
            cmdIdB = emsTaskResult.CmdIdB;
            this.StepMsg($"Ems {emsIdA}小车任务不存在，1111并创建任务a{taskA?.TaskNo}指令a：{cmdIdA},，并创建任务b{taskB?.TaskNo}指令b：{cmdIdB}");
        }



        if (cmdIdA > 0)
        {
            this.StepMsg($"Emsa {cmdIdA}小车任务存在，开始下发");
            emsATask.isExecute = false;
            emsATask.emsId = emsIdA;
            // 任务详细信息（异常、时间、X、Y）
            emsATask.bizTaskCmdXZ = taskService.GetTaskCmdXZ(cmdIdA, emsIdA);
            this.StepMsg($"Ems {emsIdA}小车任务存在，生成数据{emsATask.ToJson()}");
        }
        if (cmdIdB > 0)
        {
            this.StepMsg($"Emsb {emsIdB}小车任务存在，开始下发");
            emsBTask.isExecute = false;
            emsBTask.emsId = emsIdB;
            // 任务详细信息（异常、时间、X、Y）
            emsBTask.bizTaskCmdXZ = taskService.GetTaskCmdXZ(cmdIdB, emsIdB);
            this.StepMsg($"Ems {emsIdB}小车任务存在，生成数据{emsBTask.ToJson()}");
        }
        return (emsATask, emsBTask);
    }

    // 清理缓存
    private void ClearCache(int taskNo)
    {
        if (Cache.ATaskNo == taskNo)
        {
            Cache.ATaskNo = 0;
            this.ClearAPlc();
            return;
        }
        else if (Cache.BTaskNo == taskNo)
        {
            Cache.BTaskNo = 0;
            this.ClearBPlc();
            return;
        }
    }

    // 清理 A PLC 
    private void ClearAPlc()
    {
        this.BizData.WriteData(new
        {
            // 下传字段值
            ATaskNo = 0,
            AStartX = 0,
            AStartZ = 0,
            ASubSize = 0,
            ATargetX = 0,
            ATargetZ = 0,
            AAllowableDescent = 0,
            ATakeTire = 0,

            curFlag = 0,
        });
    }

    // 清理 B PLC
    private void ClearBPlc()
    {
        this.BizData.WriteData(new
        {
            // 下传字段值
            BTaskNo = 0,
            BStartX = 0,
            BStartZ = 0,
            BSubSize = 0,
            BTargetX = 0,
            BTargetZ = 0,
            BAllowableDescent = 0,
            BTakeTire = 0,

            curFlag = 0,
        });
    }

    /// <summary>
    /// 获取任务
    /// </summary>
    /// <param name="service"></param>
    /// <param name="emsId"></param>
    /// <returns>Ture 正在执行；False 未创建/未执行</returns>
    private (bool isExecuted, BizEmsTask task, int pairWait) IsExecuted(ITaskService service, long emsId)
    {
        var emsTask = service.GetTaskCmdByEmsId(emsId); // 小车任务

        if (emsTask is not null)
        {
            if (emsTask.IsExecuted)
            {
                return (true, emsTask, emsTask.PairWait);
            }
            else
            {
                return (false, emsTask, emsTask.PairWait);
            }
        }
        return (false, emsTask, 0);
    }


    private int SetBarCodeAB(CuringBean resultA, CuringBean resultB)
    {
        var barCodeL = "";
        var barCodeR = "";

        if (resultA is not null)
        {
            if ("R".Equals(resultA.Mode))
            {
                barCodeR = resultA.BarCode;
            }
            else
            {
                barCodeL = resultA.BarCode;
            }
        }

        if (resultB is not null)
        {
            if ("R".Equals(resultB.Mode))
            {
                barCodeR = resultB.BarCode;
            }
            else
            {
                barCodeL = resultB.BarCode;
            }
        }

        var bean = new
        {
            BarCodeL_12 = OctalTool.GetMergeAsciiToInt(barCodeL?[0], barCodeL?[1]),
            BarCodeL_34 = OctalTool.GetMergeAsciiToInt(barCodeL?[2], barCodeL?[3]),
            BarCodeL_56 = OctalTool.GetMergeAsciiToInt(barCodeL?[4], barCodeL?[5]),
            BarCodeL_78 = OctalTool.GetMergeAsciiToInt(barCodeL?[6], barCodeL?[7]),
            BarCodeL_910 = 0,

            BarCodeR_12 = OctalTool.GetMergeAsciiToInt(barCodeR?[0], barCodeR?[1]),
            BarCodeR_34 = OctalTool.GetMergeAsciiToInt(barCodeR?[2], barCodeR?[3]),
            BarCodeR_56 = OctalTool.GetMergeAsciiToInt(barCodeR?[4], barCodeR?[5]),
            BarCodeR_78 = OctalTool.GetMergeAsciiToInt(barCodeR?[6], barCodeR?[7]),
            BarCodeR_910 = 0,
        };
        //this.StepMsg($"双车完成任务：{bean.ToJson()}");

        return this.BizData.WriteData(bean);
    }
    private int SetBarCodeAorB(CuringBean result)
    {
        if (result is not null)
        {
            if ("R".Equals(result.Mode))
            {
                var barCodeL = result.BarCode;
                return this.BizData.WriteData(new
                {
                    BarCodeL_12 = OctalTool.GetMergeAsciiToInt(barCodeL?[0], barCodeL?[1]),
                    BarCodeL_34 = OctalTool.GetMergeAsciiToInt(barCodeL?[2], barCodeL?[3]),
                    BarCodeL_56 = OctalTool.GetMergeAsciiToInt(barCodeL?[4], barCodeL?[5]),
                    BarCodeL_78 = OctalTool.GetMergeAsciiToInt(barCodeL?[6], barCodeL?[7]),
                    BarCodeL_910 = 0,
                });
            }
            else
            {
                var barCodeR = result.BarCode;
                return this.BizData.WriteData(new
                {
                    BarCodeR_12 = OctalTool.GetMergeAsciiToInt(barCodeR?[0], barCodeR?[1]),
                    BarCodeR_34 = OctalTool.GetMergeAsciiToInt(barCodeR?[2], barCodeR?[3]),
                    BarCodeR_56 = OctalTool.GetMergeAsciiToInt(barCodeR?[4], barCodeR?[5]),
                    BarCodeR_78 = OctalTool.GetMergeAsciiToInt(barCodeR?[6], barCodeR?[7]),
                    BarCodeR_910 = 0,
                });
            }
        }

        return 0;
    }
    private int SetBarCode(int numA, int numB, CuringBean resultA, CuringBean resultB) => (numA, numB) switch
    {
        (1, 1) => SetBarCodeAB(resultA, resultB),
        (0, 1) => SetBarCodeAorB(resultB),
        (1, 0) => SetBarCodeAorB(resultA),
        _ => 0
    };

    class EmsBean
    {
        /// <summary>
        /// 缓存任务编号
        /// </summary>
        public int CacheTaskNo { get; set; }
        /// <summary>
        /// To 任务编号
        /// </summary>
        public int ValueTaskNo { get; set; }
        /// <summary>
        /// 完成状态【1：放胎完成】
        /// </summary>
        public int FinishFlag { get; set; }
        /// <summary>
        /// 取货位置
        /// </summary>
        public long LocId { get; set; }
        /// <summary>
        /// 小车ID
        /// </summary>
        public long EmsId { get; set; }
    }
    class EmsTaskCmd
    {
        public EmsTaskCmd(long emsId, BizTaskCmdXZ bizTaskCmdXZ)
        {
            EmsId = emsId;
            BizTaskCmdXZ = bizTaskCmdXZ;
        }

        public long EmsId { get; set; }
        public BizTaskCmdXZ BizTaskCmdXZ { get; set; }
    }
    class emsTaskCreateBean
    {
        public bool isExecute { get; set; }
        public long emsId { get; set; }
        public BizTaskCmdXZ? bizTaskCmdXZ = new BizTaskCmdXZ();
    }
}
